﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace MyControl {

  #region 联合选择框
  /// <summary>
  /// 联合选择框
  /// </summary>
  #endregion
  public partial class UnionSelector : UserControl, INotifyPropertyChanged {

	/** 组件属性 */
	#region 是否打开显示选项
	/// <summary>
	/// 是否打开显示选项
	/// </summary>
	#endregion
	public bool OptionIsOpen {
	  get {
		return this.popup.IsOpen;
	  }
	  set {
		// 初始化选项缓存
		if (value) {
		  this.removeRangeLastIndex(0);
		  this.currentTrigger = TriggerType.Open;
		  try {
			foreach (var index in this.selectIndexList) {
			  this.setOptionIndex(index);
			}
		  }
		  catch (Exception) {
		  }
		}
		this.popup.IsOpen = value;
	  }
	}

	#region 选项样式
	/// <summary>
	/// 选项样式
	/// </summary>
	#endregion
	public Style OptionStyle {
	  get {
		return this.optionStyle;
	  }
	  set {
		this.optionStyle = value;
		this.TriggerPropertyChanged("OptionStyle");
	  }
	}
	private Style optionStyle = null;

	#region 选项标签样式
	/// <summary>
	/// 选项标签样式
	/// </summary>
	#endregion
	public Style OptionLabelStyle {
	  get {
		return this.optionLabelStyle;
	  }
	  set {
		this.optionLabelStyle = value;
		this.TriggerPropertyChanged("OptionLabelStyle");
	  }
	}
	private Style optionLabelStyle = null;

	#region 分割图标样式
	/// <summary>
	/// 分割图标样式
	/// </summary>
	#endregion
	public Style OptionIconStyle {
	  get {
		return this.optionIconStyle;
	  }
	  set {
		this.optionIconStyle = value;
		this.TriggerPropertyChanged("OptionIconStyle");
	  }
	}
	private Style optionIconStyle = null;

	#region 标签样式
	/// <summary>
	/// 标签样式
	/// </summary>
	#endregion
	public Style LabelStyle {
	  get {
		return this.labelStyle;
	  }
	  set {
		this.labelStyle = value;
		this.TriggerPropertyChanged("LabelStyle");
	  }
	}
	private Style labelStyle = null;

	#region 标签名称样式
	/// <summary>
	/// 标签名称样式
	/// </summary>
	#endregion
	public Style LabelNameStyle {
	  get {
		return this.labelNameStyle;
	  }
	  set {
		this.labelNameStyle = value;
		this.TriggerPropertyChanged("LabelNameStyle");
	  }
	}
	private Style labelNameStyle = null;

	#region 分割标签样式
	/// <summary>
	/// 分割标签样式
	/// </summary>
	#endregion
	public Style LabelSeparatorStyle {
	  get {
		return this.labelSeparatorStyle;
	  }
	  set {
		this.labelSeparatorStyle = value;
		this.TriggerPropertyChanged("LabelSeparatorStyle");
	  }
	}
	private Style labelSeparatorStyle = null;

	#region 选项高度
	/// <summary>
	/// 选项高度
	/// </summary>
	#endregion
	public int? OptionHeight {
	  get {
		return this.optionHeight;
	  }
	  set {
		this.optionHeight = value;
		this.TriggerPropertyChanged("OptionHeight");
	  }
	}
	private int? optionHeight = null;

	#region 选项最大高度
	/// <summary>
	/// 选项最大高度
	/// </summary>
	#endregion
	public int? OptionMaxHeight {
	  get {
		return this.optionMaxHeight;
	  }
	  set {
		this.optionMaxHeight = value;
		this.TriggerPropertyChanged("OptionMaxHeight");
	  }
	}
	private int? optionMaxHeight = null;

	#region 选项最小高度
	/// <summary>
	/// 选项最小高度
	/// </summary>
	#endregion
	public int? OptionMinHeight {
	  get {
		return this.optionMinHeight;
	  }
	  set {
		this.optionMinHeight = value;
		this.TriggerPropertyChanged("OptionMinHeight");
	  }
	}
	private int? optionMinHeight = null;

	#region 样式变化事件
	/// <summary>
	/// 样式变化事件
	/// </summary>
	#endregion
	public event PropertyChangedEventHandler PropertyChanged;

	#region 触发选项方式
	/// <summary>
	/// 触发选项方式
	/// </summary>
	#endregion
	public ExpandTriggerType ExpandTrigger {
	  get;
	  set;
	} = ExpandTriggerType.Hover;

	#region 选项分割符文本
	/// <summary>
	/// 选项分割符文本
	/// </summary>
	#endregion
	public string Separator {
	  get; set;
	} = "/";

	#region 标签名称列表
	/// <summary>
	/// 标签名称列表
	/// </summary>
	#endregion
	public List<Label> LabelNameList {
	  get {
		var retList = new List<Label>();
		var list = this.labelElementList;
		var count = list.Count;
		for (int index = 0; index < count; index++) {
		  if (index % 2 == 0) {
			retList.Add(list[index] as Label);
		  }
		}
		return retList;
	  }
	}

	#region 选项分割标签列表
	/// <summary>
	/// 选项分割标签列表
	/// </summary>
	#endregion
	public List<Label> LabelSeparatorList {
	  get {
		var retList = new List<Label>();
		var list = this.labelElementList;
		var count = list.Count;
		for (int index = 0; index < count; index++) {
		  if (index % 2 != 0) {
			retList.Add(list[index] as Label);
		  }
		}
		return retList;
	  }
	}

	#region 选项列表
	/// <summary>
	/// 选项列表
	/// </summary>
	#endregion
	private UIElementCollection optionElementList {
	  get {
		return this.stackPanel.Children;
	  }
	}

	#region 标签列表
	/// <summary>
	/// 标签列表
	/// </summary>
	#endregion
	private UIElementCollection labelElementList {
	  get {
		return this.buttonWrapPanel.Children;
	  }
	}

	#region 触发样式变化
	/// <summary>
	/// 触发样式变化
	/// </summary>
	/// <param name="propertyName">触发名称</param>
	#endregion
	private void TriggerPropertyChanged(string propertyName) {
	  PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
	}

	#region 选中内容发生变化
	/// <summary>
	/// 选中内容发生变化
	/// </summary>
	#endregion
	public event SelectValueChangeHandler SelectValueChange;

	/** 数据 */
	#region 选项数据
	/// <summary>
	/// 选项数据
	/// </summary>
	#endregion
	private List<Tree> optionData;
	#region 选项数据
	/// <summary>
	/// 选项数据
	/// </summary>
	#endregion
	public List<Tree> OptionData {
	  get {
		return this.optionData;
	  }
	  set {
		this.optionData = value;
		this.SelectIndexList = new List<int>();
		this.appendOptionElement(value);
	  }
	}

	#region 选中的选项
	/// <summary>
	/// 选中的选项
	/// </summary>
	#endregion
	private Tree selectItem;
	#region 选中的选项
	/// <summary>
	/// 选中的选项
	/// </summary>
	#endregion
	public Tree SelectItem {
	  get {
		return this.selectItem;
	  }
	}

	#region 选中的内容
	/// <summary>
	/// 选中的内容
	/// </summary>
	#endregion
	private object selectValue;
	#region 选中的内容
	/// <summary>
	/// 选中的内容
	/// </summary>
	#endregion
	public object SelectValue {
	  get {
		return this.selectValue;
	  }
	  set {
		this.SelectIndexList = TreeUtils.FindIndexByFormatEquals(this.optionData, (tree, index, list) => {
		  if (tree.HasChildren) {
			return false;
		  }
		  return tree.Value?.Equals(value) ?? false;
		});
	  }
	}

	#region 选择序号列表
	/// <summary>
	/// 选择序号列表
	/// </summary>
	#endregion
	private List<int> selectIndexList = new List<int>();
	#region 选择序号列表
	/// <summary>
	/// 选择序号列表
	/// </summary>
	#endregion
	public List<int> SelectIndexList {
	  get {
		var selectIndexList = this.selectIndexList;
		return selectIndexList.GetRange(0, selectIndexList.Count);
	  }
	  set {
		var newSelectIndexList = value;
		Tree tree = null;
		if (newSelectIndexList == null) {
		  this.selectIndexList = new List<int>();
		}
		else {
		  // 查询更新序号列表的项
		  var selectIndexList = newSelectIndexList.GetRange(0, newSelectIndexList.Count);
		  tree = TreeUtils.FindTreeByIndex(this.optionData, selectIndexList);
		  if (tree == null) {
			return;
		  }
		  foreach (var item in this.SelectTreeList) {
			item.IsSelect = false;
		  }
		  this.selectIndexList = selectIndexList;
		  foreach (var item in this.SelectTreeList) {
			item.IsSelect = true;
		  }
		}
		// 更新按钮内容
		this.setButtonElementContent();
		// 触发 SelectItemChange
		var oldSelectItem = this.selectItem;
		this.selectItem = tree;
		// 触发 SelectValueChange
		var oldSelectValue = this.selectValue;
		this.selectValue = tree == null ? null : tree.Value;
		this.SelectValueChange?.Invoke(this, new SelectValueChangeEventArgs(this.selectValue, oldSelectValue, tree, oldSelectItem));
	  }
	}

	#region 选择序号缓存列表
	/// <summary>
	/// 选择序号缓存列表
	/// </summary>
	#endregion
	private List<int> selectTempIndexList = new List<int>();

	#region 选择名称列表
	/// <summary>
	/// 选择名称列表
	/// </summary>
	#endregion
	public List<string> SelectNameList {
	  get {
		return TreeUtils.FindFormatDataByIndex(this.optionData, this.selectIndexList, (tree, index, list)=> {
		  return tree.Name;
		});
	  }
	  set {
		this.SelectIndexList = TreeUtils.FindIndexByFormatDataEquals(this.optionData, value, (tree, index, list) => {
		  return tree.Name;
		});
	  }
	}

	#region 选择节点列表
	/// <summary>
	/// 选择节点列表
	/// </summary>
	#endregion
	public List<Tree> SelectTreeList {
	  get {
		return TreeUtils.FindTreeListByIndex(this.optionData, this.selectIndexList);
	  }
	}

	#region 当前触发方式
	/// <summary>
	/// 当前触发方式
	/// </summary>
	#endregion
	private TriggerType currentTrigger = TriggerType.Hover;

	#region 改变节点选择状态
	/// <summary>
	/// 改变节点选择状态
	/// </summary>
	/// <param name="selectIndexList">选择序号列表</param>
	#endregion
	private void changeTreeSelectState(List<int> selectIndexList) {

	}

	#region 设置按钮内容
	/// <summary>
	/// 设置按钮内容 SelectIndexList change
	/// </summary>
	#endregion
	private void setButtonElementContent() {
	  var labelNameStyle = this.LabelNameStyle;
	  var labelSeparatorStyle = this.LabelSeparatorStyle;
	  var collection = this.labelElementList;
	  collection.Clear();
	  var nameList = this.SelectNameList;
	  var count = nameList.Count;
	  if (nameList == null || count == 0) {
		return;
	  }
	  collection.Add(new Label() { Content = nameList[0], Style = labelNameStyle });
	  if (count == 1) {
		return;
	  }
	  var separator = this.Separator;
	  for (var i = 1; i < count; i++) {
		var name = nameList[i];
		collection.Add(new Label() { Content = separator, Style = labelSeparatorStyle });
		collection.Add(new Label() { Content = name, Style = labelNameStyle });
	  }
	}

	#region 更改范围_选项列表
	/// <summary>
	/// 更改范围_选项列表
	/// </summary>
	/// <param name="index">选择的列表框序号</param>
	#endregion
	private void removeRange_OptionList(int index) {
	  var list = this.optionElementList;
	  if (list == null) {
		return;
	  }
	  var count = list.Count;
	  var start = index + 1;
	  var length = count - start;
	  try {
		list.RemoveRange(start, length);
	  }
	  catch (Exception) {
		list.Clear();
	  }
	}

	#region 更改范围_选择序号列表
	/// <summary>
	/// 更改范围_选择序号列表
	/// </summary>
	/// <param name="index">选择的列表框序号</param>
	#endregion
	private void removeRange_SelectTempIndexList(int index) {
	  var list = this.selectTempIndexList;
	  var count = list.Count;
	  var start = index;
	  var length = count - start;
	  try {
		list.RemoveRange(start, length);
	  }
	  catch (Exception) {
		list.Clear();
	  }
	}

	#region 更改选择范围
	/// <summary>
	/// 更改选择范围
	/// </summary>
	/// <param name="index">选择的列表框序号</param>
	#endregion
	private void removeRangeLastIndex(int index) {
	  this.removeRange_OptionList(index);
	  this.removeRange_SelectTempIndexList(index);
	}

	#region 列表框滚动到指定索引
	/// <summary>
	/// 列表框滚动到指定索引
	/// </summary>
	/// <param name="listBox">列表框</param>
	/// <param name="index">索引</param>
	#endregion
	private void optionElementScrollToIndex(ListBox listBox, int index) {
	  var list = listBox.Items;
	  var count = list.Count;
	  if (index < 0) { index = 0; }
	  else if (index >= count) { index = count - 1; }
	  listBox.ScrollIntoView(list[index]);
	}

	#region 添加选项元素的列表子元素
	/// <summary>
	/// 添加选项元素的列表子元素
	/// </summary>
	/// <param name="list">要添加的列表子元素的数据</param>
	#endregion
	private void appendOptionElement(List<Tree> list) {
	  // 创建列表元素
	  var listBox = new ListBox();
	  // 添加数据所属元素
	  foreach (var tree in list) {
		tree.Origin = listBox;
	  }
	  // 添加列表元素选项
	  listBox.ItemsSource = list;
	  // 添加列表元素至
	  this.optionElementList.Add(listBox);
	  // 列表框获取焦点
	  listBox.Focus();
	}

	#region 选中列表框的选项
	/// <summary>
	/// 选中列表框的选项
	/// </summary>
	/// <param name="index">选中列表框选项的序号</param>
	#endregion
	private void setOptionIndex(int index) {
	  // 获取列表框数据
	  var selectTempIndexList = this.selectTempIndexList;
	  var selectTree = TreeUtils.FindChildrenByIndex(this.optionData, selectTempIndexList);
	  if (selectTree == null) {
		return;
	  }
	  // 判断选中区间是否符合条件
	  var count = selectTree.Count;
	  if (index < 0 || index >= count) {
		return;
	  }
	  // 获取选项
	  var thisTree = selectTree[index];
	  // 设置选中
	  var listBox = thisTree.Origin as ListBox;
	  listBox.SelectedIndex = index;
	  // 如果是刚刚打开 就滚动到选中的位置
	  if (this.currentTrigger == TriggerType.Open) {
		this.optionElementScrollToIndex(listBox, index);
	  }
	  // 保存选择序号
	  selectTempIndexList.Add(index);
	  // 如 当前选项是数据
	  if (!thisTree.HasChildren) {
		if (this.currentTrigger == TriggerType.Click) {
		  this.SelectIndexList = selectTempIndexList;
		  this.OptionIsOpen = false;
		}
	  }
	  // 如 当前选项是列表
	  else {
		this.appendOptionElement(thisTree.Children);
	  }
	}

	#region 选项发生变化
	/// <summary>
	/// 选项发生变化
	/// </summary>
	/// <param name="sender">触发元素</param>
	/// <param name="type">触发类型</param>
	#endregion
	private void onSelectionChanged(Tree tree) {
	  // 获取内容
	  var listBox = tree.Origin as ListBox;
	  // 获取列表框选则序号
	  var index = listBox.Items.IndexOf(tree);
	  // 获取列表元素列表
	  var elementList = this.optionElementList;
	  if (elementList == null) {
		return;
	  }
	  // 获取列表元素列表个数
	  var elementCount = elementList.Count;
	  if (elementCount == 0) {
		return;
	  }
	  // 获取列表元素序号
	  var elementIndex = elementList.IndexOf(listBox);
	  if (elementIndex == -1 || elementIndex >= elementCount) {
		return;
	  }
	  // 根据序号删除序号以后的数据
	  this.removeRangeLastIndex(elementIndex);
	  // 设置列表框选中项
	  this.setOptionIndex(index);
	}

	#region 创建联合选择框
	/// <summary>
	/// 创建联合选择框
	/// </summary>
	#endregion
	public UnionSelector() {
	  // 初始化控件
	  InitializeComponent();
	}

	/** 交互 */
	#region 选择按钮_单击
	/// <summary>
	/// 选择按钮_单击
	/// </summary>
	/// <param name="sender">触发元素</param>
	/// <param name="e">事件信息</param>
	#endregion
	private void button_Click(object sender, RoutedEventArgs e) {
	  this.OptionIsOpen = !this.OptionIsOpen;
	}

	#region 选项列表框子元素_鼠标单击
	/// <summary>
	/// 选项列表框子元素_鼠标单击
	/// </summary>
	/// <param name="sender">触发元素</param>
	/// <param name="e">事件信息</param>
	#endregion
	private void optionListBox_MouseDown(object sender, MouseButtonEventArgs e) {
	  if (e.LeftButton != MouseButtonState.Pressed) {
		return;
	  }
	  var border = sender as Grid;
	  this.currentTrigger = TriggerType.Click;
	  this.onSelectionChanged(border.DataContext as Tree);
	}

	#region 选项列表框子元素_鼠标悬停
	/// <summary>
	/// 选项列表框子元素_鼠标悬停
	/// </summary>
	/// <param name="sender">触发元素</param>
	/// <param name="e">事件信息</param>
	#endregion
	private void optionListBox_MouseEnter(object sender, MouseEventArgs e) {
	  if (this.ExpandTrigger != ExpandTriggerType.Hover) {
		return;
	  }
	  var listBoxItem = sender as Grid;
	  this.currentTrigger = TriggerType.Hover;
	  this.onSelectionChanged(listBoxItem.DataContext as Tree);
	}
  }
}
